﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Volo.Abp.AspNetCore.Mvc.Conventions;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;

namespace Ebusiness_ProductService.Models
{
    /// <summary>
    /// 商品模型
    /// </summary>
    //1、目的:高内聚，低耦合。有关系的实体紧密协作而关系很弱的实体被隔离。
    //2、把关系紧密的实体放到一个聚合中，每个聚合中有一个实体作为聚合根(Aggregate Root)，所有对于聚合内对象的访问都通过聚合根来进行，外部对象只能持有对聚合根的引用。
    //3、聚合根不仅仅是实体，还是所在聚合的管理者。
    [Table("Product")]
    public class Product : AggregateRoot<Guid>
    {
        //实体中的逻辑代码：管理实体的创建、状态等非业务逻辑代码
        //1、贫血模型一个类中只有属性或者成员变量，没有方法。
        //2、充血模型:一个类中既有属性、成员变量，也有方法。
        //需求:定义一个类保存用户的用户名、密码、积分;用户必须具有用户名;为了保证安全，密码采用密码的散列值保存;用户的初始积分为10分;每次登录成功奖励5个积分，每次登录失败扣3个积分

        //1、属性是只读的或者是只能被类内部的代码修改。
        //2、定义有参数的构造方法。
        //3、有的成员变量没有对应属性，但是这些成员变量需要映射为数据表中的列，也就是我们需要把私有成员变量映射到数据表中的列。
        //4、有的属性是只读的，也就是它的值是从数据库中读取出来的，但是我们不能修改属性值。
        //五:有的属性不需要映射到数据列，仅在运行时被使用
        //public Guid Id { set; get; } // 商品主键

        //private Product()  //提供给efcore使用的 ，efcore从数据库中读取数据然后加载生成Product使用的
        //{

        //}

        //2、定义有参数的构造方法。
        //public Product(string ProductName) //给程序员提供使用的
        //{
        //    this.Created = DateTime.Now;
        //    this.ProductName = ProductName;
        //}

        public string ProductCode { set; get; }    //商品编码

        public string ProductUrl { set; get; }         // 商品主图
        public string ProductTitle { set; get; }       //商品标题
        public string ProductDescription { set; get; }     // 图文描述
        public decimal ProductVirtualprice { set; get; } //商品虚拟价格
        public decimal ProductPrice { set; get; }       //价格
        public int ProductSort { set; get; }    //商品序号
        public int ProductSold { set; get; }        //已售件数
        public int ProductStock { set; get; }       //商品库存
        public string ProductStatus { set; get; } // 商品状态

        ////聚合:高内聚，低耦合。把关系强的实体放到同一个聚合中，把其中一个实体做为“聚合根”，对于同一个聚合内的其他实体，都通过聚合根实体进行。
        public List<ProductImage> productImages { set; get; }

        //属性是只读的或者是只能被类内部的代码修改。
        //public string ProductName { private set; get; }

        //有的成员变量没有对应属性，但是这些成员变量需要映射为数据表中的列，也就是我们需要把私有成员变量映射到数据表中的列。
        //private string passwordHash;

        //数据只能从数据库读取出来，不能修改
        //private string remark;
        //public string Remark { get { return this.remark; } } 

        //1、属性是只读的或者是只能被类内部的代码修改。
        //public DateTime? Created { get; init; }

        //有的属性不需要映射到数据列，仅在运行时被使用
        //public string Tag { get; set; }

        //充血模型:一个类中既有属性、成员变量，也有方法。
        //public void ChangeProductName(string proName)
        //{
        //    //检查用户名的合法性
        //    this.ProductName = proName;
        //}

        //有的成员变量没有对应属性，但是这些成员变量需要映射为数据表中的列，也就是我们需要把私有成员变量映射到数据表中的列。
        //public void ChangePasswordHashassword(string newPassword)
        //{
        //    if (newPassword.Length < 6)
        //    {
        //        new Exception("密码不能太短");
        //    }
        //    //this.passwordHash = hashhelper.hash(newPassword);
        //}

        //值类型，把有紧密关系的属性打包成一个独立的类型
        public Geo Geo { set; get; }

        //枚举类型，存储的是数字
        public GeoType geoType { set; get; }

        //业务中需要操作聚合根中的其他实体，需要在聚合根中定义操作聚合根中其他实体的方法
        public void AddProductImage(string productID)
        {
            //存在则修改，不存在则添加
        }
    }

    /// <summary>
    /// 经纬度
    /// </summary>
    public class Geo
    {
        public double Latitude { set; get; }

        public double Longitude { set; get; }

        private Geo()
        {  //eccore使用

        }

        public Geo(double latitude, double longitude)  //程序员使用
        {
            Latitude = latitude;
            Longitude = longitude;
        }
    }

    public enum GeoType
    {
        CNY, USF, DWD
    }
}
